#include "uart.h"
#include "stdio.h"
#include "string.h"
#include "ti_msp_dl_config.h"

#include <stdbool.h>
#include <stdint.h>

// 缓冲区配置（根据实际需求调整）
#define FRAME_BUFFER_SIZE 128 // 每帧最大长度

static char __serial_data[FRAME_BUFFER_SIZE];
static uint8_t __serial_data_idx = 0;
static bool __serial_data_available = false;

// DMA双缓冲内存区域（确保4字节对齐）
__attribute__((aligned(4))) uint8_t frameBufferA[FRAME_BUFFER_SIZE] = {0};
__attribute__((aligned(4))) uint8_t frameBufferB[FRAME_BUFFER_SIZE] = {0};

// DMA控制变量
volatile uint8_t *activeDmaBuffer = frameBufferA; // DMA当前写入的缓冲区
volatile uint8_t *readyFrame = frameBufferB;      // 主程序可读取的最新帧
volatile uint32_t frameLength = 0;                // 最新帧的长度
volatile bool frameReadyFlag = false;             // 新帧就绪标志
volatile bool bufferLock = false;                 // 缓冲区锁定状态

void serial_send_char(char ch)
{
  DL_UART_Main_transmitDataBlocking(UART_0_INST, ch);
}
void serial_send_str(char *str)
{
  while (*str != 0 && str != 0)
  {
    serial_send_char(*str++);
  }
}
void serial_send_str_with_len(char *str, uint16_t len)
{
  while (len--)
  {
    serial_send_char(*str++);
  }
}

void serial_Log_str(char *tag, char *str)
{
  serial_send_str(tag);
  serial_send_str(" : ");
  serial_send_str(str);
  serial_send_str("\n");
}

bool serial_is_available() { return __serial_data_available; }

void uart1_send_str(char *str)
{
  while (*str != 0 && str != 0)
  {
    DL_UART_Main_transmitDataBlocking(UART_1_INST, *str++);
  }
}
void uart1_send_str_with_len(uint8_t *str, uint16_t len)
{
  while (len--)
  {
    DL_UART_Main_transmitDataBlocking(UART_1_INST, *str++);
  }
}

char *serial_read_string()
{
  __serial_data_available = false;
  if (__serial_data_idx > 0)
  {
    __serial_data[__serial_data_idx] = 0;
    __serial_data_idx = 0;
    return __serial_data;
  }
  return NULL;
}

void configUARTDma(uint32_t dest_ptr, uint16_t dest_size)
{
  DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(&UART_1_INST->RXDATA));
  DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, dest_ptr);

  DL_DMA_setTransferSize(DMA, DMA_CH0_CHAN_ID, dest_size);
  DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);
}

void uart_init()
{
  NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN);
  NVIC_EnableIRQ(UART_0_INST_INT_IRQN);
  NVIC_ClearPendingIRQ(UART_1_INST_INT_IRQN);
  NVIC_EnableIRQ(UART_1_INST_INT_IRQN);
  NVIC_ClearPendingIRQ(UART_3_INST_INT_IRQN);
  NVIC_EnableIRQ(UART_3_INST_INT_IRQN);

  configUARTDma((uint32_t)activeDmaBuffer, FRAME_BUFFER_SIZE);
}
uint16_t get_frame_size(uint8_t *frame)
{
  uint16_t cnt = 0;
  while (*frame++)
    cnt++;
  return cnt;
}

uint16_t getCurrentUart1Data(uint8_t **buff_ptr)
{
  if (!frameReadyFlag)
  {
    *buff_ptr = NULL;
    return 0;
  }

  *buff_ptr = (uint8_t *)readyFrame;

  frameReadyFlag = false;
  return frameLength;
}
void setCurrentUART1DataLock(bool is_lock)
{
  bufferLock = is_lock;

  if (is_lock == false) // means current data has been processed then clear the
                        // current buffer
  {
    memset((void *)readyFrame, 0, FRAME_BUFFER_SIZE);
    frameReadyFlag = false;
  }
}

void UART_0_INST_IRQHandler(void)
{
  // simple echo
  static char ch = 0;
  switch (DL_UART_Main_getPendingInterrupt(UART_0_INST))
  {
  case DL_UART_MAIN_IIDX_RX:
    ch = DL_UART_Main_receiveData(UART_0_INST);
    __serial_data[__serial_data_idx++] = ch;
    if (ch == '\n' || ch == 0)
      __serial_data_available = true;

    break;
  default:
    break;
  }
}

void UART_1_INST_IRQHandler()
{
  switch (DL_UART_Main_getPendingInterrupt(UART_1_INST))
  {
  case DL_UART_MAIN_IIDX_RX_TIMEOUT_ERROR:
    DL_DMA_disableChannel(DMA, DMA_CH0_CHAN_ID);

    // 1. 获取当前帧长度
    frameLength = get_frame_size((uint8_t *)activeDmaBuffer);

    // read the remain data from FIFO
    while (!DL_UART_Main_isRXFIFOEmpty(UART_1_INST))
    {
      activeDmaBuffer[frameLength++] = DL_UART_Main_receiveData(UART_1_INST);
    }

    // 3. 检查缓冲区是否被主程序锁定
    if (!bufferLock)
    {
      // 4. 原子更新就绪帧信息
      readyFrame = activeDmaBuffer;
      activeDmaBuffer =
          (activeDmaBuffer == frameBufferA) ? frameBufferB : frameBufferA;
      frameReadyFlag = true;
      // serial_Log_str("uart", "buffer change");
    }
    else
    {
      serial_Log_str("uart", "discard this frame!");
      memset((void *)activeDmaBuffer, 0, FRAME_BUFFER_SIZE);
    }

    SYSCFG_DL_DMA_init();
    configUARTDma((uint32_t)activeDmaBuffer, FRAME_BUFFER_SIZE);

// for test
#if 0
        serial_Log_str("UART ready frame", (char *)readyFrame);
        serial_Log_str("UART active frame", (char *)activeDmaBuffer);
#endif
    break;
  default:
    break;
  }
}
